package com.qianfeng.iot.sdk.service.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.dc3.common.bean.driver.AttributeInfo;
import com.dc3.common.bean.driver.DriverMetadata;
import com.dc3.common.bean.driver.DriverRegister;
import com.dc3.common.constant.CommonConstant;
import com.dc3.common.model.*;
import com.dc3.common.utils.Dc3Util;
import com.qianfeng.iot.sdk.bean.driver.DriverContext;
import com.qianfeng.iot.sdk.bean.driver.DriverProperty;
import com.qianfeng.iot.sdk.service.DriverMetaDataService;
import com.qianfeng.iot.sdk.service.DriverService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Jackiechan on 2022/8/12 20:53
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */

@Service
public class DriverMetaDataServiceImpl implements DriverMetaDataService {


    @Value("${spring.application.name}")
    private String serviceName;

    @Value("${server.port}")
    private int port;

    private DriverContext driverContext;

    @Autowired
    public void setDriverContext(DriverContext driverContext) {
        this.driverContext = driverContext;
    }

    private DriverService driverService;

    @Autowired
    public void setDriverService(DriverService driverService) {
        this.driverService = driverService;
    }

    private DriverProperty driverProperty;

    @Autowired
    public void setDriverProperty(DriverProperty driverProperty) {
        this.driverProperty = driverProperty;
    }

    @Override
    public void init() {
        //把上面的基本信息发送到我们的manager 进行保存
        System.err.println("向manager发送数据,注册驱动");
        //创建驱动对象
        Driver driver = new Driver(driverProperty.getName(), serviceName, Dc3Util.localHost(), port, driverProperty.getType());
        //先搞个握手
        syncHandShake(driver);
        //发送我们的数据
        driverService.driverEventSend(new DriverEvent(serviceName, CommonConstant.Driver.Event.DRIVER_REGISTER,
                new DriverRegister(driverProperty.getTenant(), driver, driverProperty.getDriverAttribute(), driverProperty.getPointAttribute())));
        //发送完成后再同步一次
        syncDriverMetaData(driver);

    }



    @Override
    public void updateDriverStatus(String status) {
        driverContext.setDriverStatus(status);
    }

    @Override
    public void updateDriverMetaData(DriverMetadata driverMetadata) {
    driverContext.setDriverMetadata(driverMetadata);
    }

    @Override
    public void upsertProfile(Profile profile) {
        driverContext.getDriverMetadata().getProfilePointMap().computeIfAbsent(profile.getId(), key -> new ConcurrentHashMap<>(16));
    }

    @Override
    public void deleteProfile(String id) {
        driverContext.getDriverMetadata().getProfilePointMap().entrySet().removeIf(next -> next.getKey().equals(id));
    }

    @Override
    public void upsertPointInfo(PointInfo pointInfo) {
        String deviceId = pointInfo.getDeviceId();
        String pointId = pointInfo.getPointId();
        String pointAttributeId = pointInfo.getPointAttributeId();
        //根据位号属性的id取出我们的位号的属性
        PointAttribute pointAttribute = driverContext.getDriverMetadata().getPointAttributeMap().get(pointAttributeId);
        if (pointAttribute != null) {
//            Map<String, Map<String, AttributeInfo>> map1 = driverContext.getDriverMetadata().getPointInfoMap().get(deviceId);
////            if (map1 == null) {
////                map1 = new ConcurrentHashMap<>();
////                driverContext.getDriverMetadata().getPointInfoMap().put(deviceId, map1);
////            }
////            Map<String, AttributeInfo> map2 = map1.get(pointId);
////            if (map2 == null) {
////                map2 = new ConcurrentHashMap<>();
////                map1.put(pointId, map2);
////            }
////            map2.put(pointAttribute.getName(), new AttributeInfo(pointAttribute.getValue(), pointAttribute.getType()));

            driverContext.getDriverMetadata().getPointInfoMap()
                    .computeIfAbsent(deviceId,key->new ConcurrentHashMap<>())//如果deviceId对应的数据存在就获取,否则就返回后新创建的map
                    .computeIfAbsent(pointId,key->new ConcurrentHashMap<>())
                    .put(pointAttribute.getName(), new AttributeInfo(pointAttribute.getValue(), pointAttribute.getType()));
        }
    }

    @Override
    public void deletePointInfo(PointInfo pointInfo) {
        String deviceId = pointInfo.getDeviceId();
        String pointId = pointInfo.getPointId();
        String pointAttributeId = pointInfo.getPointAttributeId();
        //根据位号属性的id取出我们的位号的属性
        PointAttribute pointAttribute = driverContext.getDriverMetadata().getPointAttributeMap().get(pointAttributeId);
        if (pointAttribute != null) {
            driverContext.getDriverMetadata().getPointInfoMap()
                    .computeIfPresent(deviceId, (key, value) -> {
                        value.computeIfPresent(pointId, (key2, value2) -> {
                            value2.entrySet().removeIf(next -> next.getKey().equals(pointAttribute.getName()));
                            return null;//返回null代表删除数据
                        });
                        return null;
                    });

            driverContext.getDriverMetadata().getPointInfoMap().computeIfPresent(deviceId, (key, value) -> null);
        }
    }

    @Override
    public void upsertDevice(Device device) {
        driverContext.getDriverMetadata().getDeviceMap().put(device.getId(), device);
        //新添加设备后需要向驱动信息和位号信息里面绑定当前设备
        driverContext.getDriverMetadata().getDriverInfoMap().computeIfAbsent(device.getId(), key->new ConcurrentHashMap<>());
        driverContext.getDriverMetadata().getPointInfoMap().computeIfAbsent(device.getId(), key->new ConcurrentHashMap<>());
    }

    @Override
    public void deleteDevice(String id) {
        driverContext.getDriverMetadata().getDeviceMap().entrySet().removeIf(next -> next.getKey().equals(id));
        driverContext.getDriverMetadata().getDriverInfoMap().entrySet().removeIf(next -> next.getKey().equals(id));
        driverContext.getDriverMetadata().getPointInfoMap().entrySet().removeIf(next -> next.getKey().equals(id));
    }

    @Override
    public void upsertPoint(Point point) {
//        Map<String, Point> pointMap = driverContext.getDriverMetadata().getProfilePointMap().get(point.getProfileId());
//        if (pointMap == null) {
//            pointMap = new ConcurrentHashMap<>();
//            driverContext.getDriverMetadata().getProfilePointMap().put(point.getProfileId(),pointMap)
//        }
//        pointMap
        driverContext.getDriverMetadata().getProfilePointMap().computeIfAbsent(point.getProfileId(), key -> new ConcurrentHashMap<>())
                .put(point.getId(), point);
    }

    @Override
    public void deletePoint(Point point) {
//        Map<String, Point> stringPointMap = driverContext.getDriverMetadata().getProfilePointMap().get(point.getProfileId());
//        if (stringPointMap != null) {
//            stringPointMap.remove(point.getId())
//        }
        driverContext.getDriverMetadata().getProfilePointMap().computeIfPresent(point.getProfileId(), (key, value) -> {
            value.remove(point.getId());
            return value;
        });
    }

    @Override
    public void upsertDriverInfo(DriverInfo driverInfo) {
        DriverAttribute driverAttribute = driverContext.getDriverMetadata().getDriverAttributeMap().get(driverInfo.getDriverAttributeId());
        if (driverAttribute != null) {
            driverContext.getDriverMetadata().getDriverInfoMap().computeIfAbsent(driverInfo.getDeviceId(), key -> new ConcurrentHashMap<>())
                    .put(driverAttribute.getName(), new AttributeInfo(driverInfo.getValue(), driverAttribute.getType()));
        }
    }


    @Override
    public void deleteDriverInfo(String deviceId, DriverInfo driverInfo) {
        DriverAttribute driverAttribute = driverContext.getDriverMetadata().getDriverAttributeMap().get(driverInfo.getDriverAttributeId());
        if (driverAttribute != null) {
            driverContext.getDriverMetadata().getDriverInfoMap().computeIfPresent(driverInfo.getDeviceId(), (key, value) -> {
                value.remove(driverAttribute.getName());
//                if (value.size() <1 ){ //应该删除数据,放到下面删除了
//                    return null;
//                }
                return value;
            });
            //上面删除完成数据后,可能map就没有值了,就应该删除这个map
            driverContext.getDriverMetadata().getDriverInfoMap().entrySet().removeIf(entry -> entry.getValue().size() < 1);
        }

    }


    private void syncDriverMetaData(Driver driver) {
        //同步元数据,发送一个同步操作,manager会收到,查询数据后会给我发回来,还是通过mq发回来,我们到时候接收就行了,并不是通过响应返回的,因为我们发出去就是一个mq
        CompletableFuture.runAsync(() -> {
            driverService.driverEventSend(new DriverEvent(serviceName, CommonConstant.Driver.Event.DRIVER_METADATA_SYNC, serviceName));
        });
    }

    /**
     * 搞一次握手
     *
     * @param driver
     */
    private void syncHandShake(Driver driver) {
        //先更新状态正在注册中,因为如果我们本地记录的状态都不是在线,我们就没有必要处理数据
        driverContext.setDriverStatus(CommonConstant.Status.REGISTERING);

        CompletableFuture.runAsync(() -> {
            driverService.driverEventSend(new DriverEvent(serviceName, CommonConstant.Driver.Event.DRIVER_HANDSHAKE, null));
        });
    }
}
